package pl.edu.agh.mobsys.activities;

import java.net.InetAddress;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import pl.edu.agh.mobsys.R;
import pl.edu.agh.mobsys.XmppApplication;
import pl.edu.agh.mobsys.data.Contact;
import pl.edu.agh.mobsys.data.ContactFactory;
import pl.edu.agh.mobsys.data.SmoaContact;
import pl.edu.agh.mobsys.utils.BB;
import pl.edu.agh.mobsys.utils.Constants;
import pl.edu.agh.mobsys.utils.ContactAdapter;
import android.app.AlertDialog;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.DialogInterface.OnCancelListener;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.ContextMenu;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.view.ContextMenu.ContextMenuInfo;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.TextView;

/**
 * Widok z listą kontaktów - podstawowy widok aplikacji.
 * */
public class Contacts extends ListActivity {

	private final String TAG = "Contacts";

	private TextView empty, conStatus;
	private List<Contact> contacts;

	private ContactAdapter adapter;

	private SharedPreferences prefs;

	private int activatedContact = -1;

	private XmppApplication app;

	public String conStatusPrefix;

	private pl.edu.agh.mobsys.utils.ConnectionListener cl;

	private String CONTEXT_CHAT, CONTEXT_SMOA_CHAT, CONTEXT_EDIT,
			CONTEXT_DELETE, CONTEXT_ABORT;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		
		try {
			System.out.println(InetAddress.getByName("grass2.man.poznan.pl").getHostAddress());
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		super.onCreate(savedInstanceState);
		setContentView(R.layout.contacts);

		this.empty = (TextView) findViewById(R.id.empty);

		// zabawy z listą kontaków
		final ListView listView = getListView();
		listView.setItemsCanFocus(false);
		listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
		listView.setEmptyView(this.empty);
		registerForContextMenu(listView);

		prefs = getSharedPreferences(Constants.SHARED_PREFS_KEY_CONTACTS,
				Context.MODE_WORLD_READABLE + Context.MODE_WORLD_WRITEABLE);

		app = (XmppApplication) getApplication();

		// wyświetlanie bieżącego statusu połaczenie z serwerem XMPP
		conStatusPrefix = getResources().getString(R.string.con_status) + " ";
		conStatus = (TextView) findViewById(R.id.connection_status);
		conStatus.setText(conStatusPrefix);

		// callback - aktualizuje status połacznia
		cl = new pl.edu.agh.mobsys.utils.ConnectionListener() {

			public void connectionInactive(final String cause) {
				runOnUiThread(new Runnable() {
					public void run() {
						conStatus.setText(conStatusPrefix + "not connected: "
								+ cause);
					}
				});
			}

			public void connectionActive() {
				runOnUiThread(new Runnable() {
					public void run() {
						conStatus.setText(conStatusPrefix + "connected");
					}
				});
			}
		};

		app.setConnectionListener(cl);

		// etykiety do menu kontektowego
		CONTEXT_ABORT = getResources().getString(R.string.context_menu_abort);
		CONTEXT_SMOA_CHAT = getResources().getString(
				R.string.context_menu_smoachat);
		CONTEXT_EDIT = getResources().getString(R.string.context_menu_edit);
		CONTEXT_DELETE = getResources().getString(R.string.context_menu_delete);
		CONTEXT_CHAT = getResources().getString(R.string.context_menu_chat);
	}

	protected void onResume() {
		super.onResume();
		loadContacts();
		adapter = new ContactAdapter(getBaseContext(), contacts);
		setListAdapter(adapter);
		// zawsze próbujemy się połączyć
		if (!app.isConnected()) {
			app.tryConnect(handler);
		}
		if (app.isConnected()) {
			conStatus.setText(conStatusPrefix + "connected");
		}
	}

	/**
	 * Ładowanie listy kontatów z preferencji, gdzie są utrwalane.
	 * */
	private void loadContacts() {
		if (contacts == null) {
			contacts = new LinkedList<Contact>();
		} else {
			contacts.clear();
		}
		for (String alias : prefs.getAll().keySet()) {
			contacts.add(ContactFactory.buildContact(alias, (String) prefs
					.getAll().get(alias)));
		}
	}

	// guziki na dole
	private Set<BB> bbs = new HashSet<BB>();

	public Contacts() {
		super();
		// konfiguracja połączenia
		bbs.add(new BB(R.string.con_config, 10, -1, new Intent(
				Constants.SERVER_CONFIG)));

		// dodanie nowego kontaktu
		bbs.add(new BB(R.string.con_new_contact, 11, -1, new Intent(
				Constants.CONTACT_NEW)));

		// odświerzenie połączenia
		bbs.add(new BB(R.string.con_init_reconnect, 12, -1, null));
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		super.onCreateOptionsMenu(menu);
		for (BB bb : bbs) {
			menu.add(0, bb.id, bb.id, bb.labelId);
		}
		openMenu();
		return true;
	}

	private void openMenu() {
		this.getWindow().openPanel(Window.FEATURE_OPTIONS_PANEL,
				new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU));
	}

	@Override
	public boolean onMenuItemSelected(int featureId, MenuItem item) {
		if (bbs != null) {
			for (BB bb : bbs) {
				Log.d(TAG, "Current menu option:" + bb.id);
				if (bb.id == item.getItemId()) {
					// odświeżenie połączenia - specjalna obsługa - nie intent
					if (bb.labelId == R.string.con_init_reconnect) {
						app.reconnect(handler);
					} else {
						Log.d(TAG, "Opening [" + Integer.toString(bb.id)
								+ "] with selectied position ["
								+ activatedContact + "]");
						startActivity(bb.intent);
					}
					return true;
				}
			}
		}
		return super.onMenuItemSelected(featureId, item);
	}

	/**
	 * Usuwanie kontaktu przez popup
	 * */
	private void showDeleteConfirmationDialog() {

		AlertDialog.Builder alertbox = new AlertDialog.Builder(this);
		alertbox.setMessage(getResources()
				.getString(R.string.con_confirm_query)
				+ " \"" + contacts.get(activatedContact).getAlias() + "\"?");

		alertbox.setPositiveButton(getResources().getString(
				R.string.con_confirm_yes),
				new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface arg0, int arg1) {
						prefs.edit().remove(
								contacts.get(activatedContact).getAlias())
								.commit();
						adapter.notifyDataSetChanged();
						loadContacts();
					}
				});

		alertbox.setNegativeButton(getResources().getString(
				R.string.con_confirm_no),
				new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface arg0, int arg1) {
						; // nic się nie dzieje
					}
				});

		alertbox.show();
	}

	@Override
	/**
	 * Menu kontekstowe, redukuje ilość przycisków w menu głównym
	 * */
	public void onCreateContextMenu(ContextMenu menu, View v,
			ContextMenuInfo menuInfo) {
		AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;

		// otwarcie chatu
		if (contacts.get(info.position) instanceof SmoaContact) {
			menu.add(CONTEXT_SMOA_CHAT).setEnabled(app.isConnected());
		} else {
			menu.add(CONTEXT_CHAT).setEnabled(app.isConnected());
		}
		// edycja kontaktu
		menu.add(CONTEXT_EDIT);
		// usunięcie kontaktu
		menu.add(CONTEXT_DELETE);
		// powrót z widoku okienka z menu kontekstowych
		// można właściwie wywalić
		menu.add(CONTEXT_ABORT);

		// ładny tytuł
		menu.setHeaderTitle(contacts.get(info.position).getAlias());
	}

	@Override
	/**
	 * Obsługa zdarzeń po wyborze elementów z menu kontekstowego.
	 * */
	public boolean onContextItemSelected(MenuItem item) {
		AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item
				.getMenuInfo();
		Intent i;
		if (CONTEXT_CHAT.equals(item.getTitle())) {
			i = new Intent(Constants.CHAT);
		} else if (CONTEXT_SMOA_CHAT.equals(item.getTitle())) {
			i = new Intent(Constants.SOAP_JOBS);
		} else if (CONTEXT_EDIT.equals(item.getTitle())) {
			i = new Intent(Constants.CONTACT_EDIT);
		} else if (CONTEXT_DELETE.equals(item.getTitle())) {
			activatedContact = info.position;
			showDeleteConfirmationDialog();
			return false;
		} else {
			return true; // wyjście z menu kontekstowego
		}
		i.putExtra(Constants.ACTIVATED_CONTACT, contacts.get(info.position)
				.getAlias());
		startActivity(i);
		return true;
	}

	// dialog ze stanem połaczenia
	private ProgressDialog pd;

	// silnie związane z logiką w klasie aplikacji - dialog wyświetlający
	// asynchroniczne zdarzenia związane z nawiązywaniem połaczenia
	private final Handler handler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			if (pd == null) {
				pd = ProgressDialog.show(Contacts.this,
						"Setting up connection", "Preparing...", true, true);
				pd.setOnCancelListener(new OnCancelListener() {
					public void onCancel(DialogInterface dialog) {
						// wstrzymanie przekazywania komunikatów z aplikacji
						app.holdConnecting();
					}
				});
			} else if (!pd.isShowing()) {
				pd.show();
			}
			if (msg.obj == null) {
				// usuniecia dialogu
				pd.dismiss();
				pd = null;
			} else {
				// aktualizacja komunikatu
				pd.setMessage(msg.obj + "");
			}
		}
	};

}